home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2000 #5 / Amiga Plus CD - 2000 - No. 5.iso / Tools / Dev / fpc / demos / bezier.pas < prev    next >
Pascal/Delphi Source File  |  2000-01-01  |  7KB  |  252 lines

  1. Program Bezier;
  2.  
  3. {
  4.    This program draws Bezier curves using the degree elevation
  5.    method.  For large numbers of points (more than 10, for
  6.    example) this is faster than the recursive way.
  7. }
  8.  
  9. {
  10.    History:
  11.    Changed the source to use 2.0+.
  12.    Looks a lot better.
  13.    Added CloseWindowSafely.
  14.    Made the window dynamic, it will
  15.    adjust the size after the screen size.
  16.    9 May 1998.
  17.  
  18.    Translated the source to fpc.
  19.    20 Aug 1998.
  20.  
  21.    Changed to use TAGS and pas2c.
  22.    31 Oct 1998.
  23.  
  24.    nils.sjoholm@mailbox.swipnet.se
  25. }
  26.  
  27. uses exec, intuition, graphics, utility,vartags, pastoc;
  28.  
  29. type
  30.     PointRec = packed Record
  31.         X, Y : Real;
  32.     end;
  33.  
  34. Const
  35.     w  : pWindow  = Nil;
  36.     s  : pScreen   = Nil;
  37.  
  38. {
  39.     This will make the new look for screen.
  40.     SA_Pens, Integer(pens)
  41. }
  42.     pens : array [0..0] of integer = (not 0);
  43.  
  44. Var
  45.     rp : pRastPort;
  46.  
  47.     PointCount : Word;
  48.     Points : Array [1..200] of PointRec;
  49.  
  50.     LastX, LastY : Word;
  51.  
  52. Procedure CleanUpAndDie;
  53. begin
  54.     if assigned(w) then CloseWindow(w);
  55.     if assigned(s) then CloseScreen(s);
  56.     if assigned(Gfxbase) then CloseLibrary(GfxBase);
  57.     Halt(0);
  58. end;
  59.  
  60. Procedure DrawLine;
  61. begin
  62.     Move(rp, Trunc(Points[PointCount].X), Trunc(Points[PointCount].Y));
  63.     Draw(rp, LastX, LastY);
  64. end;
  65.  
  66. Procedure GetPoints;
  67. var
  68.     LastSeconds,
  69.     LastMicros  : Longint;
  70.     IM : pIntuiMessage;
  71.     StoreMsg : tIntuiMessage;
  72.     Leave : Boolean;
  73.     OutOfBounds : Boolean;
  74.     BorderLeft, BorderRight,
  75.     BorderTop, BorderBottom : Word;
  76.     dummy : Boolean;
  77.  
  78.     Procedure AddPoint;
  79.     begin
  80.     Inc(PointCount);
  81.     with Points[PointCount] do begin
  82.         X := Real(StoreMsg.MouseX);
  83.         Y := Real(StoreMsg.MouseY);
  84.     end;
  85.     with StoreMsg do begin
  86.         LastX := MouseX;
  87.         LastY := MouseY;
  88.         LastSeconds := Seconds;
  89.         LastMicros := Micros;
  90.     end;
  91.     SetAPen(rp, 2);
  92.     SetDrMd(rp, JAM1);
  93.     DrawEllipse(rp, LastX, LastY, 5, 3);
  94.     SetAPen(rp, 3);
  95.     SetDrMd(rp, COMPLEMENT);
  96.     DrawLine;
  97.     end;
  98.  
  99.     Function CheckForExit : Boolean;
  100.     {   This function determines whether the user wanted to stop
  101.     entering points.  I added the position tests because my
  102.     doubleclick time is too long, and I was too lazy to dig
  103.     out Preferences to change it. }
  104.     begin
  105.     with StoreMsg do
  106.         CheckForExit := DoubleClick(LastSeconds, LastMicros,
  107.                     Seconds, Micros) and
  108.                 (Abs(MouseX - Trunc(Points[PointCount].X)) < 5) and
  109.                 (Abs(MouseY - TRunc(Points[PointCount].Y)) < 3);
  110.     end;
  111.  
  112.     Procedure ClearIt;
  113.     {  This just clears the screen when you enter your first point }
  114.     begin
  115.     SetDrMd(rp, JAM1);
  116.     SetAPen(rp, 0);
  117.     RectFill(rp, BorderLeft, BorderTop,
  118.              BorderRight, BorderBottom);
  119.     SetDrMd(rp, COMPLEMENT);
  120.     SetAPen(rp, 3);
  121.     end;
  122.  
  123. begin
  124.     dummy := ModifyIDCMP(w, IDCMP_CLOSEWINDOW or IDCMP_MOUSEBUTTONS or 
  125. IDCMP_MOUSEMOVE);
  126.     SetDrMd(rp, COMPLEMENT);
  127.     PointCount := 0;
  128.     Leave := False;
  129.     OutOfBounds := False;
  130.     BorderLeft := w^.BorderLeft;
  131.     BorderRight := (w^.Width - w^.BorderRight) -1;
  132.     BorderTop := w^.BorderTop;
  133.     BorderBottom := (w^.Height - w^.BorderBottom) -1;
  134.     repeat
  135.         IM := pIntuiMessage(WaitPort(w^.UserPort));
  136.         IM := pIntuiMessage(GetMsg(w^.UserPort));
  137.         StoreMsg := IM^;
  138.         ReplyMsg(pMessage(IM));
  139.         case StoreMsg.IClass of
  140.            IDCMP_MOUSEMOVE : if PointCount > 0 then begin
  141.                  if not OutOfBounds then
  142.                  DrawLine;
  143.                      LastX := StoreMsg.MouseX;
  144.                      LastY := StoreMsg.MouseY;
  145.                  if (LastX > BorderLeft) and
  146.                 (LastX < BorderRight) and
  147.                 (LastY > BorderTop) and
  148.                 (LastY < BorderBottom) then begin
  149.                  DrawLine;
  150.                  OutOfBounds := False;
  151.                  end else
  152.                  OutOfBounds := True;
  153.                  end;
  154.            IDCMP_MOUSEBUTTONS : if StoreMsg.Code = SELECTUP then begin
  155.                     if PointCount > 0 then
  156.                     Leave := CheckForExit
  157.                 else
  158.                     ClearIt;
  159.                     if (not Leave) and (not OutOfBounds) then
  160.                     AddPoint;
  161.                     end;
  162.            IDCMP_CLOSEWINDOW : CleanUpAndDie;
  163.         end;
  164.     until Leave or (PointCount > 50);
  165.     if not Leave then
  166.         DrawLine;
  167.     dummy := ModifyIDCMP(w, IDCMP_CLOSEWINDOW);
  168.     SetDrMd(rp, JAM1);
  169.     SetAPen(rp, 1);
  170. end;
  171.  
  172. Procedure Elevate;
  173. var
  174.     t, tprime,
  175.     RealPoints : Real;
  176.     i : Integer;
  177. begin
  178.     Inc(PointCount);
  179.     RealPoints := Real(PointCount);
  180.     Points[PointCount] := Points[Pred(PointCount)];
  181.     for i := Pred(PointCount) downto 2 do
  182.     with Points[i] do begin
  183.         t := Real(i) / RealPoints;
  184.         tprime := 1.0 - t;
  185.         X := t * Points[Pred(i)].X + tprime * X;
  186.         Y := t * Points[Pred(i)].Y + tprime * Y;
  187.     end;
  188. end;
  189.  
  190. Procedure DrawCurve;
  191. var
  192.     i : Integer;
  193. begin
  194.     Move(rp, Trunc(Points[1].X), Trunc(Points[1].Y));
  195.     for i := 2 to PointCount do
  196.     Draw(rp, Round(Points[i].X), Round(Points[i].Y));
  197. end;
  198.  
  199. Procedure DrawBezier;
  200. begin
  201.     SetAPen(rp, 2);
  202.     while PointCount < 100 do begin
  203.     Elevate;
  204.     DrawCurve;
  205.     if GetMsg(w^.UserPort) <> Nil then
  206.         CleanUpAndDie;
  207.     end;
  208.     SetAPen(rp, 1);
  209.     DrawCurve;
  210. end;
  211.  
  212. begin
  213.    GfxBase := OpenLibrary(GRAPHICSNAME,37);
  214.  
  215.    s := OpenScreenTagList(nil, TAGS(SA_Pens,      Long(@pens),
  216.       SA_Depth,     2,
  217.       SA_DisplayID, HIRES_KEY,
  218.       SA_Title,     Longstr('Simple Bezier Curves'),
  219.       TAG_END));
  220.     
  221.     if s = NIL then CleanUpAndDie;
  222.  
  223.       w := OpenWindowTagList(nil, TAGS(
  224.       WA_IDCMP,        IDCMP_CLOSEWINDOW,
  225.       WA_Left,         0,
  226.       WA_Top,          s^.BarHeight +1,
  227.       WA_Width,        s^.Width,
  228.       WA_Height,       s^.Height - (s^.BarHeight + 1),
  229.       WA_DepthGadget,  ltrue,
  230.       WA_DragBar,      ltrue,
  231.       WA_CloseGadget,  ltrue,
  232.       WA_ReportMouse,  ltrue,
  233.       WA_SmartRefresh, ltrue,
  234.       WA_Activate,     ltrue,
  235.       WA_Title,        longstr('Close the Window to Quit'),
  236.       WA_CustomScreen, long(s),
  237.       TAG_END));
  238.     
  239.     IF w=NIL THEN CleanUpAndDie;
  240.  
  241.     rp := w^.RPort;
  242.     Move(rp, 252, 30);
  243.     Text(rp, pas2c('Enter points by pressing the left mouse button'), 46);
  244.     Move(rp, 252, 40);
  245.     Text(rp, pas2c('Double click on the last point to begin drawing'), 47);
  246.     repeat
  247.         GetPoints;  { Both these routines will quit if }
  248.         DrawBezier; { the window is closed. }
  249.     until False;
  250.     CleanUpAndDie;
  251. end.
  252.